#include <vcl.h>
#pragma hdrstop

#include <math.h>
#include "CDBGrid.h"
#include "CDate.h"
#include "eic.h"
#include "ctrldb.hrc"
#include <stack>
#include <dbtables.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
#include "CEdit.h"
//---------------------------------------------------------------------------
// ValidCtrCheck est utilisé pour être sûr que les composants créés ne
// contiennent aucune fonction virtuelle pure.
//
PACKAGE_CTRLDB int nCountCEdit=0;
static inline void ValidCtrCheck(CDBGrid *)
{
    new CDBGrid(NULL);
}
//---------------------------------------------------------------------------
void __fastcall MySetParent( CCustomEdit *pEdit, TWinControl *pwcParent)
{
  pEdit->Parent = pwcParent;
  if( pwcParent==NULL) return;
  POINT pt = { pEdit->Left, pEdit->Top };
  if( ::ChildWindowFromPoint( pwcParent->Handle, pt)==pwcParent->Handle) {
    pEdit->Parent = NULL;
    pEdit->Parent = pwcParent;
  }
}
//---------------------------------------------------------------------------
const char *idxTemporary = "idxTemporary";
//---------------------------------------------------------------------------
__fastcall CDBGrid::CDBGrid(TComponent* Owner)
    : TCustomDBGrid(Owner)
{
  HWND hwndDesktop   = ::GetDesktopWindow();
  HDC  hdcDesktop    = ::GetDC( hwndDesktop);

  m_ColAutoResize   = EmptyStr;
  m_ModeStandard    = false;
  m_ReadOnly        = false;
  m_bBicolor        = false;
  m_bCritical       = false;
  m_bSortTable      = false;
  m_bInitSort       = false;
  m_Enabled         = true;
  m_HeaderHeight    = -1;
  m_ColResize       = -1;
  m_TotalCol        = NULL;
  m_EcartCol        = NULL;
  m_Container       = NULL;
  m_LibelleTotal    = NULL;
  m_LibelleEcart    = NULL;
  m_Color           = clWindow;
  m_nSizeEspace     = 10;
  m_pfOnClickEvent  = NULL;
  m_pfldCurrentIdx  = NULL;
  m_nColOnMouseDown = -1;
  m_eColorFirst     = COLOR_FIRST_LINE;
  m_eColorSecond    = COLOR_SECOND_LINE;
  m_nBitsPerPixel   = ::GetDeviceCaps( hdcDesktop, BITSPIXEL); ::ReleaseDC( hwndDesktop, hdcDesktop);
  m_pOnDrawTitle    = NULL;
  m_bRedrawFlag     = true;
  WantInsert        = true;
  WantDelete        = true;

  m_pwcFind           = NULL;
  m_sbNext            = NULL;
  m_sbPrior           = NULL;
  m_pFindCol          = NULL;
  m_lstFindUnusedCol  = NULL;
  m_lstFindUnusedCol  = new TStringList();
  m_bDestroyContainer = false;
  m_Reference         = EmptyStr;

  TFontStyles sFontStyles = TitleFont->Style;
  sFontStyles << fsBold;
  TitleFont->Style = sFontStyles;

  TCustomDBGrid::OnCellClick = EvOnCellClick;

  try {
    m_TotalCol     = new TStringList;
    m_LibelleTotal = new TLabel( this/*NULL*/);  // Si vous voulez réactiver le NULL prévenez Xavier
    m_EcartCol     = new TStringList;
    m_LibelleEcart = new TLabel( this/*NULL*/);  // Si vous voulez réactiver le NULL prévenez Xavier

    m_TotalCol->OnChanging = EvTotalColOnChanging;
    m_TotalCol->OnChange   = EvTotalColOnChange;
    m_EcartCol->OnChanging = EvEcartColOnChanging;
    m_EcartCol->OnChange   = EvEcartColOnChange;
  } catch (...) {
  }
}
//---------------------------------------------------------------------------
#define DetruitCEdit( cedit) try{ if(cedit) {(cedit)->Parent = NULL; delete cedit;} }catch(Exception &e){}

__fastcall CDBGrid::~CDBGrid()
{
  DeleteTemporaryIndex();

  /*for( CMapFind::iterator it = m_mapEdit.begin(); !m_mapEdit.empty(); it = m_mapEdit.begin())
  {
    DetruitCEdit( it->second);
    m_mapEdit.erase( it);
    nCountCEdit--;
  }
  for(int i=0; i<m_TotalCol->Count; i++)
  {
    DetruitCEdit( (CEdit*)(m_TotalCol->Objects[i]));
    nCountCEdit--;
  }
  for(int i=0; i<m_EcartCol->Count; i++)
  {
    DetruitCEdit( (CEdit*)(m_EcartCol->Objects[i]));
    nCountCEdit--;
  }*/

  if (m_TotalCol) {delete m_TotalCol; m_TotalCol = NULL; }
  if (m_EcartCol) {delete m_EcartCol; m_EcartCol = NULL; }
  if (m_lstFindUnusedCol) {delete m_lstFindUnusedCol; }
}
//---------------------------------------------------------------------------
Currency __fastcall CDBGrid::GetTotal( const AnsiString strFieldName) const
{
  try {
    for(int i=0; i<m_TotalCol->Count; i++) {
      if( m_TotalCol->Strings[i]==strFieldName) {
        int        nPos;
        AnsiString strMontant(((CCustomEdit*)m_TotalCol->Objects[i])->Text);
        while(( nPos=strMontant.Pos( AnsiString( ThousandSeparator)))!=0) strMontant = strMontant.Delete( nPos, 1);
        while(( nPos=strMontant.Pos(                            " "))!=0) strMontant = strMontant.Delete( nPos, 1);
        return strMontant.ToDouble();
      }
    }
  } catch( Exception &e) {
  }
  return 0;
}
Currency __fastcall CDBGrid::GetEcart( const AnsiString strFieldName) const
{
  try {
    for(int i=0; i<m_EcartCol->Count; i++) {
      if( m_EcartCol->Strings[i]==strFieldName) {
        int        nPos;
        AnsiString strMontant((( CCustomEdit*)m_EcartCol->Objects[i])->Text);
        while(( nPos=strMontant.Pos( AnsiString( ThousandSeparator)))!=0) strMontant = strMontant.Delete( nPos, 1);
        while(( nPos=strMontant.Pos(                            " "))!=0) strMontant = strMontant.Delete( nPos, 1);
        return strMontant.ToDouble();
      }
    }
  } catch( Exception &e) {
  }
  return 0;
}
//---------------------------------------------------------------------------
Currency __fastcall CDBGrid::GetFieldTotal( TField *pField) const
{
    return GetTotal(pField->FieldName);
}
Currency __fastcall CDBGrid::GetFieldEcart( TField *pField) const
{
    return GetEcart(pField->FieldName);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetColAutoResize( const AnsiString strValue)
{
  m_ColAutoResize = strValue;
  ResizeColumnAutoResize();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetModeStandard( bool bValue)
{
  m_ModeStandard = bValue;
  Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetHeaderHeight( int nValue)
{
  m_HeaderHeight =    nValue;
  RowHeights[0]  = (( nValue==-1) || !Options.Contains( dgTitles)) ? DefaultRowHeight : nValue;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetTotalCol(TStringList *value)
{
  m_TotalCol->Assign(value);
}
void __fastcall CDBGrid::SetEcartCol(TStringList *value)
{
  m_EcartCol->Assign(value);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetContainer(TWinControl *value)
{
  m_Container = value;
  ChangeEditPosition();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetReadOnly( bool bValue)
{
  m_ReadOnly              = bValue;
  TCustomDBGrid::ReadOnly = bValue;
  if( InplaceEditor && !m_ModeStandard)
      InplaceEditor->Brush->Color = m_ReadOnly?FixedColor:clWindow;
  Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetEnabled( bool bValue)
{
  m_Enabled              = bValue;
  TCustomDBGrid::Enabled = m_Enabled;
  Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetBicolor( bool bValue)
{
  m_bBicolor = bValue;
  RedrawRows();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetColor( TColor eColor)
{
  m_Color = eColor;
  TCustomDBGrid::Color = eColor;
  Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetColorFirst( TColor eColor)
{
  m_eColorFirst = eColor;
  RedrawRows();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetColorSecond( TColor eColor)
{
  m_eColorSecond = eColor;
  RedrawRows();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetTotal( const AnsiString &strFieldName, const Currency &curValue)
{
  AnsiString     strName;
  TNumericField *fldNumeric;
  CEdit         *pEdit;

    for(int i=0; i<m_TotalCol->Count; i++) {
      strName    = m_TotalCol->Strings[i];
      pEdit      = ( CEdit*)m_TotalCol->Objects[i]; ASSERT( pEdit);
      fldNumeric = NULL;

      if( strName!=strFieldName) continue;

      if( DataSource && DataSource->DataSet && DataSource->DataSet->Active)
        fldNumeric = dynamic_cast<TNumericField*>( DataSource->DataSet->FindField( strName));

      if( fldNumeric) {
        switch( fldNumeric->DataType) {
          case ftSmallint :
          case ftInteger  : if( fldNumeric->DisplayFormat.IsEmpty())
                                 pEdit->Text = ( int)curValue;
                            else pEdit->Text = FormatFloat( fldNumeric->DisplayFormat, curValue);
                            break;
          case ftFloat    : pEdit->Text = FormatFloat( fldNumeric->DisplayFormat, curValue);
                            break;
          case ftBCD      :
          case ftCurrency : pEdit->Text = FloatToStrF( curValue, ffCurrency, 16, CurrencyDecimals);
                            break;
          default         : ASSERT( false);
                            break;
        }
      } else
        pEdit->Text = FloatToStrF( curValue, ffCurrency, 16, CurrencyDecimals);

      break;
    }
}
void __fastcall CDBGrid::SetEcart( const AnsiString &strFieldName, const Currency &curValue)
{
  AnsiString     strName;
  TNumericField *fldNumeric;
  CEdit         *pEdit;

    for(int i=0; i<m_EcartCol->Count; i++) {
      strName    = m_EcartCol->Strings[i];
      pEdit      = ( CEdit*)m_EcartCol->Objects[i]; ASSERT( pEdit);
      fldNumeric = NULL;

      if( strName!=strFieldName) continue;

      if( DataSource && DataSource->DataSet && DataSource->DataSet->Active)
        fldNumeric = dynamic_cast<TNumericField*>( DataSource->DataSet->FindField( strName));

      if( fldNumeric) {
        switch( fldNumeric->DataType) {
          case ftSmallint :
          case ftInteger  : if( fldNumeric->DisplayFormat.IsEmpty())
                                 pEdit->Text = ( int)curValue;
                            else pEdit->Text = FormatFloat( fldNumeric->DisplayFormat, curValue);
                            break;
          case ftFloat    : pEdit->Text = FormatFloat( fldNumeric->DisplayFormat, curValue);
                            break;
          case ftBCD      :
          case ftCurrency : pEdit->Text = FloatToStrF( curValue, ffCurrency, 16, CurrencyDecimals);
                            break;
          default         : ASSERT( false);
                            break;
        }
      } else
        pEdit->Text = FloatToStrF( curValue, ffCurrency, 16, CurrencyDecimals);

      break;
    }
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetFieldTotal( TField *pField, const Currency &curValue)
{
    ASSERT( pField);
    SetTotal( pField->FieldName, curValue);
}
void __fastcall CDBGrid::SetFieldEcart( TField *pField, const Currency &curValue)
{
    ASSERT( pField);
    SetEcart( pField->FieldName, curValue);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::ClearTotal( const AnsiString &strColName)
{
  if (strColName.IsEmpty()) {
    // Le nom de la colonne est vide alors on efface tous les champs
    for(int i=m_TotalCol->Count-1; i>=0; i--) {
      (( CEdit*)m_TotalCol->Objects[i])->Text = EmptyStr;
    }
  } else {
    // Recherche de l'edit sous la colonne strColName est efface le champ
    for(int i=0; i<m_TotalCol->Count; i++) {
      if (m_TotalCol->Strings[i]==strColName) {
          (( CEdit*)m_TotalCol->Objects[i])->Text = EmptyStr;
        break;
      }
    }
  }
}
void __fastcall CDBGrid::ClearEcart( const AnsiString &strColName)
{
  if (strColName.IsEmpty()) {
    // Le nom de la colonne est vide alors on efface tous les champs
    for(int i=m_EcartCol->Count-1; i>=0; i--) {
      (( CEdit*)m_EcartCol->Objects[i])->Text = EmptyStr;
    }
  } else {
    // Recherche de l'edit sous la colonne strColName est efface le champ
    for(int i=0; i<m_EcartCol->Count; i++) {
      if (m_EcartCol->Strings[i]==strColName) {
          (( CEdit*)m_EcartCol->Objects[i])->Text = EmptyStr;
        break;
      }
    }
  }
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::ClearTotal( TField *pField)
{
  ClearTotal(pField==NULL ? EmptyStr : pField->FieldName);
}
void __fastcall CDBGrid::ClearEcart( TField *pField)
{
  ClearEcart(pField==NULL ? EmptyStr : pField->FieldName);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::ResizeColumnAutoResize()
{
    if (m_ColAutoResize.IsEmpty()) return;

    int      nWidth, nWidthAuto;
    TColumn *pCol = NULL;

    // Calcule la taille libre pour afficher les colonnes
    nWidth = TCustomDBGrid::Width - ::GetSystemMetrics(SM_CXVSCROLL);
    if (BorderStyle == bsSingle)       nWidth -= 3;
    if (Options.Contains(dgIndicator)) nWidth -= IndicatorWidth + 2;

    // Calcule la taille prise par l'ensemble des colonnes
    for(int i=0; i<Columns->Count; i++) {
        if (Columns->Items[i]->Visible) {
            nWidth -= Columns->Items[i]->Width + 1;
            if (Columns->Items[i]->FieldName == m_ColAutoResize)
                pCol = Columns->Items[i];
        }
    }

    // Si on n'a pas trouvé la colonne qui doit se retailler
    // alors on quitte la fonction
    if (!pCol) return;

    nWidthAuto = pCol->Width;

    if (nWidth>0) {
        nWidth += nWidthAuto;
    } else {
        if((nWidth+=nWidthAuto)<80) {
            if( nWidthAuto > 80) {
                nWidth = 80;
            } else {
                return;
            }
        }
    }

    if (pCol->Width!=nWidth) pCol->Width = nWidth - 1;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::ChangeEditPosition()
{
  CEdit *tmpEdit;
  int    nLeft, nCurGridCol,ColTotal = -1;
  bool   bFindCol;

  if( ComponentState.Contains( csDestroying)) return;
  if( !m_bRedrawFlag) return;

  if( !Visible) return;

  try {
  // Change la position des sous-totaux
  for(int nGridCol=0; nGridCol<Columns->Count; nGridCol++) {
    if(( m_TotalCol->IndexOf( Columns->Items[nGridCol]->FieldName)!=-1) && Columns->Items[nGridCol]->Visible)
    {
      ColTotal = nGridCol;
      break;
    }
  }
  for(int i=0; i<m_TotalCol->Count; i++) {
    nLeft    = (Options.Contains(dgIndicator) ? Left+IndicatorWidth+2 : Left);
    bFindCol = false;
    tmpEdit = ( CEdit*)m_TotalCol->Objects[i];
    for(int nGridCol=0; nGridCol<Columns->Count; nGridCol++) {
      nCurGridCol = (Options.Contains(dgIndicator) ? nGridCol+1 : nGridCol);
      if (Columns->Items[nGridCol]->FieldName==m_TotalCol->Strings[i]) {
        if ((nCurGridCol>=LeftCol) && (nCurGridCol<=(LeftCol+VisibleColCount))) {
          bFindCol        = true;
          tmpEdit->Left   = nLeft + 1;
          tmpEdit->Width  = Columns->Items[nGridCol]->Width + 1;
          tmpEdit->Top    = (m_Container ? 2 : Top + Height + 0);
          MySetParent( tmpEdit, m_Container ? m_Container : Parent);
          // Affichage du libelle des totaux
          if (nGridCol==ColTotal) {
            int nLibelLeft = nLeft - Canvas->TextWidth(m_Libelle) - m_nSizeEspace;
            if (nLibelLeft>=0) {
              m_LibelleTotal->Font->Assign(Font);
              m_LibelleTotal->Caption = m_Libelle;
              m_LibelleTotal->Left    = nLibelLeft;
              m_LibelleTotal->Top     = (m_Container ? 6 : Top + Height + 4);
              m_LibelleTotal->Parent  = (m_Container ? m_Container : Parent);
              m_LibelleTotal->Transparent = true;
            } else
              m_LibelleTotal->Parent = NULL;
          }
        } else
          tmpEdit->Parent = NULL;
      }
      if (nCurGridCol>=LeftCol) nLeft += Columns->Items[nGridCol]->Width + 1;
    }
    if ( !bFindCol && tmpEdit) tmpEdit->Parent = NULL;
  }
  if (ColTotal==-1)
    m_LibelleTotal->Parent = NULL;
  ColTotal = -1;
  for(int nGridCol=0; nGridCol<Columns->Count; nGridCol++) {
    if(( m_EcartCol->IndexOf( Columns->Items[nGridCol]->FieldName)!=-1) && Columns->Items[nGridCol]->Visible)
    {
      ColTotal = nGridCol;
      break;
    }
  }
  if (ColTotal != -1)
  for(int i=0; i<m_EcartCol->Count; i++) {
    nLeft    = (Options.Contains(dgIndicator) ? Left+IndicatorWidth+2 : Left);
    bFindCol = false;
    tmpEdit = ( CEdit*)m_EcartCol->Objects[i];
    for(int nGridCol=0; nGridCol<Columns->Count; nGridCol++) {
      nCurGridCol = (Options.Contains(dgIndicator) ? nGridCol+1 : nGridCol);
      if (Columns->Items[nGridCol]->FieldName==m_EcartCol->Strings[i]) {
        if ((nCurGridCol>=LeftCol) && (nCurGridCol<=(LeftCol+VisibleColCount))) {
          bFindCol        = true;
          tmpEdit->Left   = nLeft + 1;
          tmpEdit->Width  = Columns->Items[nGridCol]->Width + 1;
          tmpEdit->Top    = (m_Container ? 2 : Top + Height + 0) + 21;
          MySetParent( tmpEdit, m_Container ? m_Container : Parent);
          // Affichage du libelle des totaux
          if (nGridCol==ColTotal) {
            int nLibelLeft = nLeft - Canvas->TextWidth(m_LibelleEc) - m_nSizeEspace;
            if (nLibelLeft>=0) {
              m_LibelleEcart->Font->Assign(Font);
              m_LibelleEcart->Caption = m_LibelleEc;
              m_LibelleEcart->Left    = nLibelLeft;
              m_LibelleEcart->Top     = (m_Container ? 6 : Top + Height + 4) + 21;
              m_LibelleEcart->Parent  = (m_Container ? m_Container : Parent);
              m_LibelleEcart->Transparent = true;
            } else
              m_LibelleEcart->Parent = NULL;
          }
        } else
          tmpEdit->Parent = NULL;
      }
      if (nCurGridCol>=LeftCol) nLeft += Columns->Items[nGridCol]->Width + 1;
    }
    if ( !bFindCol && tmpEdit) tmpEdit->Parent = NULL;
  }

  if (ColTotal==-1)
    m_LibelleEcart->Parent = NULL;
  // Appelle l'évènement OnMoveUserCol afin que l'utilisateur
  // puisse bouger ses controles
  if (m_OnMoveUserCol) m_OnMoveUserCol(this);

  } catch( Exception &e) {
    ShowMessage( e.Message);
  }
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::EvTotalColOnChanging( TObject *Sender)
{
  m_TotalCol->OnChanging = NULL;
  m_TotalCol->OnChange   = NULL;
  for(int i=0; i<m_TotalCol->Count; i++)
  {
    delete ( CEdit*)m_TotalCol->Objects[i];
    nCountCEdit--;
  }
  m_TotalCol->OnChanging = EvTotalColOnChanging;
  m_TotalCol->OnChange   = EvTotalColOnChange;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::EvTotalColOnChange( TObject *Sender)
{
  CEdit *pEdit;

  m_TotalCol->OnChanging = NULL;
  m_TotalCol->OnChange   = NULL;
  for(int i=0; i<m_TotalCol->Count; i++) {
    pEdit = new CEdit( NULL/*this*/);
    nCountCEdit++;
    pEdit->ReadOnly   = true;
    pEdit->Alignment  = taRightJustify;
    pEdit->ParentFont = false;

    m_TotalCol->Objects[i] = pEdit;
  }
  ChangeEditPosition();
  m_TotalCol->OnChanging = EvTotalColOnChanging;
  m_TotalCol->OnChange   = EvTotalColOnChange;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::EvEcartColOnChanging( TObject *Sender)
{
  m_EcartCol->OnChanging = NULL;
  m_EcartCol->OnChange   = NULL;
  for(int i=0; i<m_EcartCol->Count; i++)
  {
    delete ( CEdit*)m_EcartCol->Objects[i];
    nCountCEdit--;
  }
  m_EcartCol->OnChanging = EvEcartColOnChanging;
  m_EcartCol->OnChange   = EvEcartColOnChange;
}
void __fastcall CDBGrid::EvEcartColOnChange( TObject *Sender)
{
  CEdit *pEdit;

  m_EcartCol->OnChanging = NULL;
  m_EcartCol->OnChange   = NULL;
  for(int i=0; i<m_EcartCol->Count; i++) {
    pEdit = new CEdit( NULL/*this*/);
    nCountCEdit++;
    pEdit->ReadOnly   = true;
    pEdit->Alignment  = taRightJustify;
    pEdit->ParentFont = false;

    m_EcartCol->Objects[i] = pEdit;
  }
  ChangeEditPosition();
  m_EcartCol->OnChanging = EvEcartColOnChanging;
  m_EcartCol->OnChange   = EvEcartColOnChange;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::DefaultDrawTitle( TColumn *pColumn, const TRect &ARect, TGridDrawState AState)
{
  bool       bTableActive;
  AnsiString strTitle;

  // Recherche letexte à afficher dans la case
  Canvas->Font->Assign( TitleFont);
  bTableActive = ( DataSource && DataSource->DataSet && DataSource->DataSet->Active);
  if ( ComponentState.Contains( csDesigning) && ( Columns->State==csDefault) && !bTableActive)
       strTitle = EmptyStr;
  else strTitle = pColumn->Title->Caption;
  // Calcule la position du texte à afficher
  TRect r; r.Left   = ARect.Left   + 1;
           r.Top    = ARect.Top    + 1;
           r.Right  = ARect.Right  - 1;
           r.Bottom = ARect.Bottom - 1;
  RECT rc = RECT( r);
  Canvas->Brush->Style = bsClear;
  ::DrawText( Canvas->Handle, strTitle.c_str(), strTitle.Length(), &rc, DT_CALCRECT + DT_CENTER + DT_WORDBREAK + DT_EXTERNALLEADING);
  r.Top = r.Top + ((r.Bottom - r.Top)/2) - ((rc.bottom - rc.top)/2); rc = RECT( r);
  // Affiche le texte dans la case
  if (!m_Enabled && !m_ModeStandard) {
    Canvas->Brush->Style = bsClear;
    Canvas->Font ->Color = clBtnHighlight; ::DrawText( Canvas->Handle, strTitle.c_str(), strTitle.Length(), &rc, DT_CENTER + DT_WORDBREAK + DT_EXTERNALLEADING);
    Canvas->Font ->Color = clBtnShadow; r.Top--; r.Left--; r.Right--; rc = RECT( r);
         ::DrawText( Canvas->Handle, strTitle.c_str(), strTitle.Length(), &rc, DT_CENTER + DT_WORDBREAK + DT_EXTERNALLEADING);
  } else ::DrawText( Canvas->Handle, strTitle.c_str(), strTitle.Length(), &rc, DT_CENTER + DT_WORDBREAK + DT_EXTERNALLEADING);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::DrawCell(int ACol, int ARow, const TRect &ARect, TGridDrawState AState)
{
  bool       bDrawColTitle = (Options.Contains(dgIndicator) ? ACol>0 : true);
  int        nIndexColumn;

  if( AState.Contains(gdFixed) && (ARow==0) && bDrawColTitle) {
    nIndexColumn = (Options.Contains(dgIndicator) ? ACol-1 : ACol);
    // Dessine le fond de la case avec l'effet 3D
    Canvas->Brush->Color = FixedColor;
    Canvas->FillRect(ARect);
    Canvas->Pen ->Color  = clBtnShadow;
    Canvas->MoveTo(ARect.Right - 1, ARect.Top    + 1);
    Canvas->LineTo(ARect.Right - 1, ARect.Bottom - 1);
    Canvas->LineTo(ARect.Left     , ARect.Bottom - 1);
    Canvas->Pen ->Color  = clBtnHighlight;
    Canvas->LineTo(ARect.Left     , ARect.Top);
    Canvas->LineTo(ARect.Right    , ARect.Top);

    if( m_bSortTable && ( m_pfldCurrentIdx==Columns->Items[nIndexColumn]->Field))
      DrawGridArrowUpDown( Canvas, ( TRect&)ARect, m_bDescendingIdx ? ARROW_UP : ARROW_DOWN);


    if ( m_pOnDrawTitle) m_pOnDrawTitle( this, Columns->Items[nIndexColumn], ARect, AState);
                    else DefaultDrawTitle( Columns->Items[nIndexColumn], ARect, AState);
  } else {
    TColor eColor, eSaveColor;

    if (( m_Enabled && !m_ReadOnly) || m_ModeStandard) {
      if ( m_bBicolor && ( m_nBitsPerPixel>8)) eColor = ( ARow ^ m_nToto) & 1 ? m_eColorFirst : m_eColorSecond;
                                          else eColor = m_Color;
    } else                                     eColor = FixedColor;

    if ( m_bBicolor) {
      m_bCritical = true;
      eSaveColor = TCustomDBGrid::Color;
    }

    TCustomDBGrid::Color = eColor;
    TCustomDBGrid::DrawCell( ACol, ARow, ARect, AState);
    if ( m_bBicolor) TCustomDBGrid::Color = eSaveColor;
    m_bCritical = false;
  }
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::CMColorChanged( TMessage &Msg)
{
  if ( !m_bCritical) TCustomDBGrid::Dispatch( &Msg);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::MouseDown(TMouseButton Button, TShiftState Shift, int X, int Y)
{
  TGridCoord  Cell     = MouseCoord( X, Y);

  if ( OnMouseDown) OnMouseDown( this, Button, Shift, X, Y);
  TCustomDBGrid::MouseDown(Button, Shift, X, Y);

  if (!DataSource || (Button!=mbLeft)) return;

  int nXCol = ((!Options.Contains(dgIndicator)) ? 1 : IndicatorWidth + 1);
  // Recherche sur quelle colonne le bouton de la souris a été enfoncé
  m_nColOnMouseDown = -1;
  for(int i=LeftCol; i<ColCount; i++) {
    nXCol += ColWidths[i];
    if (nXCol>=X) { m_nColOnMouseDown = ((!Options.Contains(dgIndicator)) ? i : i-1); break; }
  }
  // Recherche la colonne qui risque d'être retaillé
  if (FGridState==gsColSizing) {
    nXCol = ((!Options.Contains(dgIndicator)) ? 2 : IndicatorWidth + 2);
    for(int i=LeftCol; i<(LeftCol+VisibleColCount); i++) {
      nXCol += (ColWidths[i]+1);
      if (nXCol>=(X-4)) { m_ColResize = ((!Options.Contains(dgIndicator)) ? i : i-1); return; }
    }
    m_ColResize = -1;
  }
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::MouseUp(TMouseButton Button, TShiftState Shift, int X, int Y)
{
  if (DataSource && (Button==mbLeft)) {
    // Renvoie le message comme quoi une colonne à été déplacé
    if (m_ColResize!=-1) {
      TCustomDBGrid::MouseUp(Button, Shift, X, Y);
      if (Columns->Items[m_ColResize]->FieldName!=m_ColAutoResize)
        ResizeColumnAutoResize();
      ChangeEditPosition();
      if (m_OnColResize) m_OnColResize(this, Columns->Items[m_ColResize]);
      m_ColResize = -1;
      return;
    }
  }

  TCustomDBGrid::MouseUp(Button, Shift, X, Y);
  ChangeEditPosition();
}
//---------------------------------------------------------------------------
bool __fastcall CDBGrid::CanEditAcceptKey( char cKey)
{
  #define CURRENCY_MAX_LENGTH 14

  bool bAncestorResult = TCustomDBGrid::CanEditAcceptKey( cKey);

  if ( bAncestorResult) {
    ASSERT( SelectedField);
    ASSERT( InplaceEditor);
    if  ( (SelectedField->DataType==ftCurrency) || (SelectedField->DataType==ftBCD)){
      InplaceEditor->ClearSelection();
      AnsiString strChar( cKey);
      AnsiString strValue( InplaceEditor->Text);
      Currency   curValue;

      if ( strValue.Length()>=CURRENCY_MAX_LENGTH) return false;
      if (( cKey=='-') && strValue.IsEmpty()) return bAncestorResult;
      strValue.Insert( strChar, InplaceEditor->SelStart+1);

      int nPosVirgule = strValue.Pos( DecimalSeparator);
      if  ( nPosVirgule>( CURRENCY_MAX_LENGTH-CurrencyDecimals)) return false;
      if (( nPosVirgule==0) && ( strValue.Length()>( CURRENCY_MAX_LENGTH-CurrencyDecimals-1))) return false;

      // Permet de supprimer par exemple le fait de taper 2 points virgules
      try                       { curValue = strValue.ToDouble(); }
      catch ( EConvertError &e) { bAncestorResult = false;        }
    }
  }

  return bAncestorResult;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetEditText( int nCol, int nRow, const AnsiString strValue)
{
  if (!SelectedField) { TCustomDBGrid::SetEditText( nCol, nRow, strValue); return; }

  AnsiString strNewValue( InplaceEditor->Text);
  //------------ Currency
  if ( (SelectedField->DataType==ftCurrency) || (SelectedField->DataType==ftBCD)){
    // Tronque les 'Currency' à 2 chiffres après la virgule
    int nPos = strNewValue.Pos( DecimalSeparator);
    if ( nPos) {
      if ( nPos+CurrencyDecimals<=strNewValue.Length()) {
        strNewValue = strNewValue.SubString( 1, nPos+CurrencyDecimals);
      }
    }
    try { Currency curTest( strNewValue); } catch( ...) { strNewValue = EmptyStr; }
  }
  //------------ TDateTime
  if ( SelectedField->DataType==ftDate) {
    if (( strNewValue.Length()>2) && ( strNewValue[3]!='/'))
      strNewValue.Insert( "/", 3);
    if (( strNewValue.Length()>5) && ( strNewValue[6]!='/'))
      strNewValue.Insert( "/", 6);

    int nYear;
    try {
      nYear = strNewValue.SubString( 7, strNewValue.Length()-6).ToInt();
      if ( nYear<DATE_MAX_ANNEES2000) nYear = nYear + 2000;
      else if ( nYear<100) nYear = nYear + 1900;

      strNewValue.Delete( 7, strNewValue.Length()-6);
      strNewValue.Insert( AnsiString( nYear), 7);
    } catch( ...) {
    }

    try {
      TDateTime( strNewValue, TDateTime::Date);
    } catch ( EConvertError &e) {
      strNewValue = EmptyStr;
    }
  }
  //------------ Float
  if ( SelectedField->DataType==ftFloat) {
    try { double dTest = strNewValue.ToDouble(); } catch( ...) { strNewValue = EmptyStr; }
  }
  //------------ Integer/SmallInt
  if(( SelectedField->DataType==ftInteger) || ( SelectedField->DataType==ftSmallint)) {
    try { int nTest = strNewValue.ToInt(); } catch( ...) { strNewValue = EmptyStr; }
  }

  TCustomDBGrid::SetEditText( nCol, nRow, strNewValue);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::DoEnter()
{
  TCustomDBGrid::DoEnter();

  TCustomForm *pForm = GetParentForm( this);
  if( pForm && dynamic_cast<CForm*>( pForm))
   (( CForm*)pForm)->GridInsert = m_bWantInsert;

  // Essaye de corriger le problème de la multi-sélection :
  // Lorsque l'on arrive sur un écran avec des enregistrements dans la grille, la première ligne
  // est sélectionnée mais le SelectedRows->Count vaut 0
  if( Options.Contains( dgMultiSelect) && DataSource && DataSource->DataSet &&
    ( DataSource->DataSet->RecordCount>0) && ( SelectedRows->Count==0)) SelectedRows->CurrentRowSelected = true;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::ColExit()
{
  TCustomDBGrid::ColExit();
}
//---------------------------------------------------------------------------
bool __fastcall CDBGrid::CanFocus()
{
  bool bCanFocus = true;

  // N'accepte pas la focalisation de la grille si l'utilisateur a demandé
  // de ne pas avoir d'insertion et que celle-ci est vide
  if( !m_bWantInsert && DataSource && DataSource->DataSet &&
      DataSource->DataSet->Active && DataSource->DataSet->IsEmpty()) bCanFocus = false;

  return ( bCanFocus && TCustomDBGrid::CanFocus());
}
//---------------------------------------------------------------------------
AnsiString __fastcall CDBGrid::GetFieldValue( int nACol)
{
  return TCustomDBGrid::GetFieldValue( nACol);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::EvOnCellClick(TColumn *pColumn)
{
  if ( !m_pfOnClickEvent) return;

  if ( Options.Contains( dgRowSelect)) {
   if ( m_nColOnMouseDown!=-1) m_pfOnClickEvent( Columns->Items[m_nColOnMouseDown]);
  } else                       m_pfOnClickEvent( pColumn);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::MoveColumn(int FromIndex, int ToIndex)
{
  ColumnMoved(FromIndex, ToIndex);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::GetPosColumn(TField *pField, int &nLeft, int &nWidth, bool &bVisible)
{
  if( pField)
    GetPosColumn(pField->FieldName, nLeft, nWidth, bVisible);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::GetPosColumn(const AnsiString &szColName, int &nLeft_, int &nWidth, bool &bVisible)
{
  int      nLeft = (Options.Contains(dgIndicator) ? Left+IndicatorWidth+2 : Left);
  int      nCurGridCol;
  TColumn *pColumn;

  // Initialisation des variables par défaut
  nLeft_ = nWidth = 0; bVisible = false;

  for(int nGridCol=0; nGridCol<Columns->Count; nGridCol++) {
    nCurGridCol = (Options.Contains(dgIndicator) ? nGridCol+1 : nGridCol);
    pColumn     =  Columns->Items[nGridCol];
    if (pColumn->FieldName==szColName) {
      if ((nCurGridCol>=LeftCol) && (nCurGridCol<=(LeftCol+VisibleColCount))) {
          nLeft_   = nLeft + 1;
          nWidth   = pColumn->Width + 1;
          bVisible = nWidth > 0;
      } else bVisible = false;
      return;
    }
    if (nCurGridCol>=LeftCol) nLeft += pColumn->Width + 1;
  }
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::MoveUserTotal(TField *pField, TWinControl *pWinCtrl)
{
  if( pField)
    MoveUserTotal(pField->FieldName, pWinCtrl);
}
void __fastcall CDBGrid::MoveUserEcart(TField *pField, TWinControl *pWinCtrl)
{
  if( pField)
    MoveUserEcart(pField->FieldName, pWinCtrl);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::MoveUserTotal( const AnsiString &strColName, TWinControl *pWinCtrl)
{
  int  nLeft, nWidth;
  bool bVisible;

  GetPosColumn( strColName, nLeft, nWidth, bVisible);
  pWinCtrl->Left    = nLeft;
  pWinCtrl->Width   = nWidth;
  pWinCtrl->Visible = bVisible;
}
void __fastcall CDBGrid::MoveUserEcart( const AnsiString &strColName, TWinControl *pWinCtrl)
{
  int  nLeft, nWidth;
  bool bVisible;

  GetPosColumn( strColName, nLeft, nWidth, bVisible);
  pWinCtrl->Left    = nLeft;
  pWinCtrl->Width   = nWidth;
  pWinCtrl->Visible = bVisible;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::MoveUserLabel(TControl *pWinCtrl)
{
  if (m_LibelleTotal->Parent!=NULL) {
       pWinCtrl->Left = m_LibelleTotal->Left;
       pWinCtrl->Visible = true;    }
  else pWinCtrl->Visible = false;
}
//---------------------------------------------------------------------------
TInplaceEdit* __fastcall CDBGrid::CreateEditor()
{
  TInplaceEdit *pEditor = TCustomDBGrid::CreateEditor();
  if( m_ReadOnly && !m_ModeStandard)
    pEditor->Brush->Color = FixedColor;
  return pEditor;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::KeyPress( char &Key)
{
  if(( Key=='.') && ( (SelectedField->DataType==ftCurrency) || (SelectedField->DataType==ftBCD))) Key = DecimalSeparator;
  if ( Key=='*') {
    // Recherche le TColum associé au champ actuellement sélectionné
    TColumn *pColumn = NULL;
    for( int i=0; i<Columns->Count; i++)
      if ( Columns->Items[i]->Field==SelectedField) { pColumn=Columns->Items[i]; break; }
    // Si le Column est du style cbsEllipsis, on génère l'évènement 'EditButtonClick'
    if ( pColumn && ( pColumn->ButtonStyle==cbsEllipsis)) { EditButtonClick(); Key = '\0'; }
  }
  TCustomDBGrid::KeyPress( Key);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::KeyDown( Word &Key, TShiftState Shift)
{
  int nRecNo;

  if( !m_bWantInsert) {
    if ( Key==VK_INSERT) Key = '\0';
    if ( Key==VK_TAB   ) Key = '\0';
    if(( Key==VK_DOWN  ) && !Options.Contains( dgRowSelect)) {
      ASSERT( DataSource);
      TDataSet *pDataSet = DataSource->DataSet;
      ASSERT( pDataSet);
      ASSERT( pDataSet->Active);

      if(( pDataSet->State==dsEdit) || ( pDataSet->State==dsInsert))
           pDataSet->Post();

               pDataSet->DisableControls();
      nRecNo = pDataSet->RecNo;
               pDataSet->Next();
      if(( nRecNo==pDataSet->RecNo) || ( nRecNo==-1)) Key = '\0';
              else pDataSet->Prior();
      pDataSet->EnableControls();
    }
  }

  if( !m_bWantDelete && ( Key==VK_DELETE) && Shift.Contains( ssCtrl)) Key = '\0';

  TCustomDBGrid::KeyDown( Key, Shift);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::Scroll( int nDistance)
{
  TCustomDBGrid::Scroll( nDistance);
  m_nToto = ( m_nToto + nDistance) & 1;
  if ( m_bBicolor) RedrawRows();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::WMSize( TWMSize &Msg)
{
  TCustomDBGrid::Dispatch(&Msg);

  // La scrollbar verticale disparait lorsque l'on passe d'une grille pleine (avec ascenseur)
  // à une grille vide si colautoresize est complété : on force son réaffichage
//  if (!m_ColAutoResize.IsEmpty())  ShowScrollBar(this->Handle, SB_VERT, true);

  // Retaille la colonne AutoResize
  ResizeColumnAutoResize();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::WMPaint( TWMPaint &Msg)
{
  HeaderHeight = m_HeaderHeight; // Repositionne la taille de la première colonne
                                 // car elle est à repris sa taille originale
  ResizeColumnAutoResize();
  TCustomDBGrid::Dispatch(&Msg);
  ChangeEditPosition();          // Repositionne les Edits
  DrawFindEdit();

  if( Columns->Count && !m_bInitSort) {
    for( int i=0; ( i<Columns->Count) && !SortColumn( Columns->Items[i]); i++);
    if( m_bSortTable && DataSource && DataSource->DataSet && DataSource->DataSet->Active) DataSource->DataSet->First();
    m_bInitSort = true;
  }
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::WMWindowPosChanged( TWMWindowPosChanged &Msg)
{
  TCustomDBGrid::Dispatch(&Msg);
  ChangeEditPosition();
  DrawFindEdit();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::WMSetRedraw( TWMSetRedraw &Msg)
{
  TCustomDBGrid::Dispatch(&Msg);
  m_bRedrawFlag = Msg.Redraw;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::CMVisibleChanged( TMessage &Msg)
{
  TCustomDBGrid::Dispatch( &Msg);

  if( !Visible) {
    for( int i=0; i<m_TotalCol->Count; i++)
      (( CEdit*)m_TotalCol->Objects[i])->Parent = NULL;
    m_LibelleTotal->Parent = NULL;
    for( int i=0; i<m_EcartCol->Count; i++)
      (( CEdit*)m_EcartCol->Objects[i])->Parent = NULL;
    m_LibelleEcart->Parent = NULL;
  }
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::WMVScrollAndWMMouseWheel( TMessage &Msg)
{
  if(  DataSource && DataSource->DataSet &&
    (( DataSource->DataSet->State==dsInsert) || ( DataSource->DataSet->State==dsEdit))) {
    Msg.Result = 1;
    return;
  }
  TCustomDBGrid::Dispatch( &Msg);
}
//---------------------------------------------------------------------------
bool __fastcall CDBGrid::DoMouseWheel( TShiftState Shift, int WheelDelta, const TPoint &MousePos)
{
  if(  DataSource && DataSource->DataSet &&
    (( DataSource->DataSet->State==dsInsert) || ( DataSource->DataSet->State==dsEdit))) return false;
  return TCustomDBGrid::DoMouseWheel( Shift, WheelDelta, MousePos);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::ShowEditor( void)
{
  TCustomDBGrid::ShowEditor();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::RedrawRows( void)
{
  int n = UpdateLock;
  for( int i=0; i<n; i++) EndUpdate();
  SendMessage( Handle, WM_SIZE, SIZE_RESTORED, ( Height << 16) | Width);
  for( int i=0; i<n; i++) BeginUpdate();
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Fonctions pour la recherche sur les colonnes - 22/08/2001
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetFindContainer( TCustomGroupBox *pWinCtrl)
{
  #define BUTTON_TOP 11

  m_pwcFind = pWinCtrl;
  // Dessine le bouton de la recherche de l'élément suivant
  if( !m_sbNext) {
    m_sbNext = new TSpeedButton( this);
    m_sbNext->Height  /= 2;
    m_sbNext->Width    = ::GetSystemMetrics( SM_CXVSCROLL);
    m_sbNext->Top      = BUTTON_TOP + m_sbNext->Height + 1;
    m_sbNext->Flat     = true;
    m_sbNext->ShowHint = true;
    m_sbNext->Hint     = "Suivant";
    m_sbNext->OnClick  = OnFindNextClick;
    m_sbNext->Glyph->LoadFromResourceID(( int)HInstance, IDB_NEXT);
  }

  // Dessine le bouton de la recherche de l'élément précédent
  if( !m_sbPrior) {
    m_sbPrior = new TSpeedButton( this);
    m_sbPrior->Height  /= 2;
    m_sbPrior->Width    = ::GetSystemMetrics( SM_CXVSCROLL);
    m_sbPrior->Top      = BUTTON_TOP;
    m_sbPrior->Flat     = true;
    m_sbPrior->ShowHint = true;
    m_sbPrior->Hint     = "Précédent";
    m_sbPrior->OnClick = OnFindPriorClick;
    m_sbPrior->Glyph->LoadFromResourceID(( int)HInstance, IDB_PRIOR);
  }

  if( !m_bDestroyContainer) {
    m_sbNext ->Parent = m_pwcFind;
    m_sbPrior->Parent = m_pwcFind;
    if( !m_pwcFind) {
      // Enlève tous les edits du container
      for( CMapFind::iterator it=m_mapEdit.begin(); it!=m_mapEdit.end(); it++)
        ( *it).second->Parent = NULL;
    } else
      DrawFindEdit();
  }
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetFindUnusedCol( const AnsiString strValue)
{
  m_lstFindUnusedCol->CommaText = strValue;
  DrawFindEdit();
}
//---------------------------------------------------------------------------
AnsiString __fastcall CDBGrid::GetFindUnusedCol()
{
  return m_lstFindUnusedCol->CommaText;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::DrawFindEdit()
{
  std::stack< CMapFind::iterator> stackDel;

  if( !m_pwcFind) return;

  // Efface tous les edits qui ne sont plus utlisés
  for( CMapFind::iterator it=m_mapEdit.begin(); it!=m_mapEdit.end(); it++) {
    bool bFind = false;
    for( int i=0; i<Columns->Count; i++) { if( Columns->Items[i]==(*it).first) { bFind=true; break; }}
    if( !bFind) stackDel.push( it);
  }
  for( ; !stackDel.empty(); stackDel.pop()) {
    CMapFind::iterator it = stackDel.top();
    delete ( it->second);
    nCountCEdit--;
    m_mapEdit.erase( it);
  }

  // Positionne les edits de recherche sous leur colonne respective.
  // Création de l'edit si nécessaire
  int nLeft   = ( Options.Contains( dgIndicator) ? Left + IndicatorWidth + 2 : Left) + 2;
  int nCurCol = Options.Contains( dgIndicator) ? 1 : 0;
  for( int i=0; i<Columns->Count; i++, nCurCol++) {

    CCustomEdit             *pedFind = NULL;
    CMapFind::iterator it = m_mapEdit.find( Columns->Items[i]);
    if( it==m_mapEdit.end()) {
      pedFind = new CEdit(NULL/*this*/);
      nCountCEdit++;
      ((CEdit*)pedFind)->ParentFont = false;
      ((CEdit*)pedFind)->OnChange   = OnFindEditChange;
      ((CEdit*)pedFind)->OnKeyPress = OnFindEditKeyPress;
      ((CEdit*)pedFind)->Top        = 13;

      m_mapEdit.insert( CMapFind::value_type( Columns->Items[i], pedFind));
    } else
      pedFind = ( *it).second;
    // Positionne et redimensionne l'edit
    if(( nCurCol>=LeftCol) && ( nCurCol<=( LeftCol + VisibleColCount))) {
      pedFind->Left   = nLeft;
      pedFind->Width  = Columns->Items[i]->Width;
      MySetParent(pedFind, ((( pedFind->Left + pedFind->Width) <= m_pwcFind->Width) && ( m_lstFindUnusedCol->IndexOf( Columns->Items[i]->FieldName)==-1) ? m_pwcFind : NULL));
      nLeft          += Columns->Items[i]->Width + 1;
      if( Columns->Items[i]->Field) {
        switch( Columns->Items[i]->Field->DataType) {
          case ftString   : ((CEdit*)pedFind)->MaxLength = Columns->Items[i]->Field->Size; break;
          case ftFloat    :
          case ftBCD      :
          case ftCurrency : ((CEdit*)pedFind)->MaxLength = 15; break;
          case ftDate     :
          case ftDateTime : if( !dynamic_cast< CDate*>( pedFind)) {
                              CDate *pedDate = new CDate( NULL);
                              pedDate->ParentFont = false;
                              pedDate->OnChange   = OnFindEditChange;
                              pedDate->OnKeyPress = OnFindEditKeyPress;
                              pedDate->Top        = 13;
                              pedDate->DateFormats = eJJMMAAAA;
                              pedDate->Left  = pedFind->Left;
                              pedDate->Width = pedFind->Width;
                              MySetParent(pedDate, pedFind->Parent);
                              delete pedFind;
                              m_mapEdit.erase( m_mapEdit.find( Columns->Items[i]));
                              m_mapEdit.insert( CMapFind::value_type( Columns->Items[i], pedDate));
                              pedFind = pedDate;
                            }
                            break;
          default         : ((CEdit*)pedFind)->MaxLength =  0; break;
        }
      }
    } else {
      pedFind->Parent = NULL;
    }
  }
  // Repositionne aussi le bouton de recherche du prochaine élement
  if( m_sbNext)
      m_sbNext->Left  = Width - m_sbNext->Width  - 2;
  if( m_sbPrior)
      m_sbPrior->Left = Width - m_sbPrior->Width - 2;
  // Tri les edits
  SortFindEdits();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::OnFindEditChange( TObject *pSender)
{
  CEdit *pedFind = dynamic_cast<CEdit*>( pSender);
  CDate *pedFindDate = NULL;
  if (!pedFind)
    pedFindDate = dynamic_cast<CDate*>( pSender);
  ASSERT( pedFind || pedFindDate);
  if (pedFind)
    if( pedFind->Text.IsEmpty()) return;
  if (pedFindDate)
    if( pedFindDate->Text.IsEmpty()) return;

  m_pFindCol = NULL;
  // Efface tous les champs edits sauf celui en cours de saisie
  for( CMapFind::iterator it=m_mapEdit.begin(); it!=m_mapEdit.end(); it++)
    if( pSender!=( *it).second) ( *it).second->Text = EmptyStr;
                           else m_pFindCol = ( *it).second->Text.IsEmpty() ? NULL : ( *it).first;

  // Recherche
  LocateNext( true);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::OnFindEditKeyPress( TObject *pSender, char &cKey)
{
  if( m_pFindCol && Columns->FindItemID( m_pFindCol->ID) && m_pFindCol->Field && (( m_pFindCol->Field->DataType==ftCurrency) || ( m_pFindCol->Field->DataType==ftBCD) || ( m_pFindCol->Field->DataType==ftFloat)) && ( cKey=='.'))
    cKey = DecimalSeparator;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::OnFindNextClick( TObject *pSender)
{
  LocateNext();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::OnFindPriorClick( TObject *pSender)
{
  bool      bFind  = false;
  TDataSet *pTable = DataSource ? DataSource->DataSet : NULL;
  if( !m_pFindCol || !pTable) return;

  AnsiString strText( m_mapEdit[m_pFindCol]->Text.UpperCase());
  AnsiString strBookmark( pTable->Bookmark);
  bool       bCurrency =( m_pFindCol->Field->DataType==ftCurrency) || ( m_pFindCol->Field->DataType==ftBCD);
  TDataChangeEvent evSaveDataChange;
  TDataSetNotifyEvent evSaveAfterScroll, evSaveBeforeScroll;

  if( Options.Contains( dgMultiSelect)) SelectedRows->Clear();

  Currency curText;
  if( bCurrency) { try { curText = strText.ToDouble(); } catch( Exception &e) { } }

  pTable->DisableControls();
  evSaveDataChange   = DataSource->OnDataChange; DataSource->OnDataChange = NULL;
  evSaveAfterScroll  = DataSource->DataSet->AfterScroll;  DataSource->DataSet->AfterScroll = NULL;
  evSaveBeforeScroll = DataSource->DataSet->BeforeScroll; DataSource->DataSet->BeforeScroll = NULL;
  if( evSaveBeforeScroll) evSaveBeforeScroll( DataSource->DataSet);

  for( pTable->Prior(); !pTable->Bof; pTable->Prior()) {
    if( bCurrency) {
      if( m_pFindCol->Field->AsCurrency==curText) { bFind=true; break; }
    } else
      if( m_pFindCol->Field->AsString.UpperCase().Pos( strText)==1) { bFind=true; break; }
  }

  if( !bFind)
    pTable->Bookmark = strBookmark;

  DataSource->OnDataChange   = evSaveDataChange;
  if( evSaveDataChange) evSaveDataChange( DataSource, NULL);
  DataSource->DataSet->BeforeScroll = evSaveBeforeScroll;
  DataSource->DataSet->AfterScroll  = evSaveAfterScroll;
  if( evSaveAfterScroll) evSaveAfterScroll( DataSource->DataSet);
  pTable->EnableControls();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::LocateNext( bool bFirstFind)
{
  bool      bFind  = false;
  TDataSet *pTable = DataSource ? DataSource->DataSet : NULL;
  if( !m_pFindCol || !pTable) return;

  Currency   curText;
  AnsiString strText( m_mapEdit[m_pFindCol]->Text);
  AnsiString strBookmark( pTable->Bookmark);
  bool       bCurrency =( m_pFindCol->Field->DataType==ftCurrency) || ( m_pFindCol->Field->DataType==ftBCD);
  bool       bIsTextAc =( RemoveAccents( strText)!=strText);
  TDataChangeEvent evSaveDataChange;
  TDataSetNotifyEvent evSaveAfterScroll, evSaveBeforeScroll;

  strText = strText.UpperCase();
  if( Options.Contains( dgMultiSelect)) SelectedRows->Clear();

  pTable->DisableControls();
  evSaveDataChange   = DataSource->OnDataChange; DataSource->OnDataChange = NULL;
  evSaveAfterScroll  = DataSource->DataSet->AfterScroll;  DataSource->DataSet->AfterScroll = NULL;
  evSaveBeforeScroll = DataSource->DataSet->BeforeScroll; DataSource->DataSet->BeforeScroll = NULL;
  if( evSaveBeforeScroll) evSaveBeforeScroll( DataSource->DataSet);

  if( !bIsTextAc && bFirstFind && m_pFindCol->Field->DataType==ftString) {
    bFind = pTable->Locate( m_pFindCol->Field->FieldName, strText.c_str(), TLocateOptions() << loPartialKey << loCaseInsensitive);
  } else {
    if( bCurrency) { try { curText = strText.ToDouble(); } catch( Exception &e) { } }
    for( bFirstFind ? pTable->First() : pTable->Next(); !pTable->Eof; pTable->Next()) {
      if( bCurrency) {
        if( !m_pFindCol->Field->IsNull && ( m_pFindCol->Field->AsCurrency==curText)) { bFind=true; break; }
      } else
        if( m_pFindCol->Field->AsString.UpperCase().Pos( strText)==1) { bFind=true; break; }
    }
  }

  if( !bFind) {
    if( bFirstFind) pTable->First();
               else pTable->Bookmark = strBookmark;
  }
  DataSource->OnDataChange = evSaveDataChange;
  if( evSaveDataChange) evSaveDataChange( DataSource, NULL);
  DataSource->DataSet->BeforeScroll = evSaveBeforeScroll;
  DataSource->DataSet->AfterScroll  = evSaveAfterScroll;
  if( evSaveAfterScroll) evSaveAfterScroll( DataSource->DataSet);

  pTable->EnableControls();
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::ClearFindEdits()
{
  for( CMapFind::iterator it=m_mapEdit.begin(); it!=m_mapEdit.end(); it++)
     ( *it).second->Text = EmptyStr;
  m_pFindCol = NULL;  //Permettra à OnFindEditKeyPress de ne pas planter si la colonne a été détruite entre temps (cf colonne N° de dossier dans la liste des dossiers/Maintenance dans le Menufed)
}
//---------------------------------------------------------------------------
int __fastcall LeftSort( void *pItem1, void *pItem2)
{
  return ((( TWinControl*)pItem1)->Left - (( TWinControl*)pItem2)->Left);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SortFindEdits()
{
  TList *pEditList = NULL;
  try {
    pEditList = new TList();
    // Création d'une liste contenant tous les objets 'Controls'
    for( int i=0; i<m_pwcFind->ControlCount; i++)
      if( dynamic_cast< TWinControl*>( m_pwcFind->Controls[i])) pEditList->Add( m_pwcFind->Controls[i]);
    // Tri par leur 'Left' croissant
    pEditList->Sort( LeftSort);
    // Modifie le TabOrder
    for( int i=0; i<pEditList->Count; i++)
      (( TWinControl*)pEditList->Items[i])->TabOrder = i;
  } catch( Exception &e) {
  }
  delete pEditList;
}
//---------------------------------------------------------------------------
CCustomEdit *__fastcall CDBGrid::GetFindEdit( TField *pfld)
{
  for( CMapFind::iterator it=m_mapEdit.begin(); it!=m_mapEdit.end(); it++)
    if(( *it).first->Field==pfld) return ( *it).second;
  return NULL;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::Notification( TComponent *pComponent, TOperation Operation)
{
  m_bDestroyContainer = true;
  if( !ComponentState.Contains( csDestroying) && ( Operation==opRemove) && ( pComponent==FindContainer))
    FindContainer = NULL;
  TCustomDBGrid::Notification( pComponent, Operation);
  m_bDestroyContainer = false;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::DeleteTemporaryIndex()
{
  if( !DataSource || !m_bSortTable) return;

  TTable *ptblIndexed = dynamic_cast< TTable*>( DataSource->DataSet);
  if( ptblIndexed) {
     bool bDelete = true;
     if( ComponentState.Contains( csDestroying)) {
       #ifdef _DEBUG
         // Si la grille et la table appartiennent tous les à la même fiche,
         // il faut vérifier que la table soit bien fermé pour éviter toute plante
         if(( Owner==ptblIndexed->Owner) && ptblIndexed->Active)
           ::EICErreur( "Message DEBUG : La table '" + ptblIndexed->TableName + "' n'a pas été fermée durant la destruction de la fiche !\nCela peut provoquer une plante lorque la table est triée grâce une grille.");
       #endif
       bDelete = (( ptblIndexed->State==dsBrowse) || ( ptblIndexed->State==dsInactive));
     }
   #ifdef _DEBUG
     if( !bDelete) ::EICErreur( "Message DEBUG : Impossible de supprimer l'index de tri sur une table en mode insertion ou modification !");
   #endif
     if( bDelete) {
       ptblIndexed->DisableControls();
       ptblIndexed->IndexName = EmptyStr;
       try { ptblIndexed->DeleteIndex( idxTemporary); } catch( EDBEngineError &e) {}
       ptblIndexed->EnableControls();
     }
  }
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetTemporaryIndex( TField *pfldIndex)
{
  AnsiString strOldFieldName;
  AnsiString strCurrentIndexName;
  AnsiString strIndexName( idxTemporary);

  if( !m_bSortTable || ComponentState.Contains( csDesigning)) return;

  // Récupère la table correcpondante
  TTable *ptblIndexed = dynamic_cast< TTable*>( pfldIndex->DataSet);
  if( ptblIndexed && ptblIndexed->Active) {
  #ifdef _DEBUG
    if( !ptblIndexed->Exclusive) {
      ::EICAttention( "Le tri sur la table ne peut se faire que sur une table en mode exclusif !\nTable : " +
                    ( ptblIndexed->Owner ? ptblIndexed->Owner->Name : AnsiString( "???")) + "->" + ptblIndexed->Name);
      return;
    }
    ptblIndexed->IndexDefs->Update();
    if( ptblIndexed->IndexDefs->Count==0) {
      ::EICAttention( "Impossible de trier la table car elle ne possède pas d'index primaire!\nTable : " +
                    ( ptblIndexed->Owner ? ptblIndexed->Owner->Name : AnsiString( "???")) + "->" + ptblIndexed->Name);
      return;
    }
  #endif

    m_pfldCurrentIdx       = pfldIndex;
    strCurrentIndexName    = ptblIndexed->IndexName;
    ptblIndexed->IndexName = EmptyStr;
    try {
                           ptblIndexed->IndexDefs->Update();
      TIndexDef *pidxDef = ptblIndexed->IndexDefs->Find( strCurrentIndexName);
      strOldFieldName    =  pidxDef->Fields;
      m_bDescendingIdx   = !pidxDef->Options.Contains( ixDescending) && ( pfldIndex->FieldName==strOldFieldName);
    } catch( Exception &e) {
    }
    ptblIndexed->DisableControls();
    DeleteTemporaryIndex();
    try {
      ptblIndexed->AddIndex( strIndexName, pfldIndex->FieldName, TIndexOptions() << ixCaseInsensitive, m_bDescendingIdx ? pfldIndex->FieldName : EmptyStr);
    } catch( EDBEngineError &e) {
      // Si une exception est déclenchée cela est sûrement à l'existance d'un index secondaire identique
      // On recherche l'index identique a celui que l'on désire créer
      strIndexName = ptblIndexed->IndexDefs->FindIndexForFields( pfldIndex->FieldName)->Name;
    }
    ptblIndexed->IndexName = strIndexName;
    ptblIndexed->EnableControls();
    m_bInitSort = true;
  }
}
//---------------------------------------------------------------------------
bool __fastcall CDBGrid::SortColumn( TColumn *pColumn)
{
  TStrings *pCols = new TStringList();
            pCols->CommaText = m_strSortUnused;
  bool      bChangeIndex     = ( pCols->IndexOf( pColumn->FieldName)==-1);
         pCols->Clear();
  delete pCols;

  if( bChangeIndex) SetTemporaryIndex( pColumn->Field);

  return bChangeIndex;
}
//---------------------------------------------------------------------------
bool __fastcall CDBGrid::SortedField( TField *pField, bool bDecroissant)
{
 if( !SortTable) return false;

  for( int i=0; i<Columns->Count; i++) {
    if( Columns->Items[i]->Field==pField) {
      if( bDecroissant) return SortColumn( Columns->Items[i]) && SortColumn( Columns->Items[i]);
                   else return SortColumn( Columns->Items[i]);
    }
  }
  return false;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::GetSortedFieldBookmark( TSortedFieldBookmark &eBookmark)
{
  eBookmark.pField      = m_pfldCurrentIdx;
  eBookmark.bDescending = m_bDescendingIdx;
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetSortedFieldBookmark( TSortedFieldBookmark &eBookmark)
{
  SortedField( eBookmark.pField, eBookmark.bDescending);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::TitleClick( TColumn *pColumn)
{
  SortColumn( pColumn);
  TCustomDBGrid::TitleClick( pColumn);
}
//---------------------------------------------------------------------------
void __fastcall CDBGrid::SetSortTable( bool bValue)
{
  if( m_bSortTable==bValue) return;

  m_bInitSort      = false;
  m_pfldCurrentIdx = NULL;
  m_bDescendingIdx = false;
  if( !ComponentState.Contains( csDesigning)) {
    if( bValue) { m_bSortTable = bValue; Repaint(); }
           else DeleteTemporaryIndex();
  }
  m_bSortTable = bValue;
}
//---------------------------------------------------------------------------
AnsiString __fastcall CDBGrid::GetReference( void)
{
  return Reference;
}
//---------------------------------------------------------------------------
namespace Cdbgrid
{
    void __fastcall PACKAGE Register()
    {
        TComponentClass classes[1] = {__classid(CDBGrid)};
        RegisterComponents("EIC CtrlDB", classes, 0);
    }
}
//---------------------------------------------------------------------------

void __fastcall CDBGrid::AutoSelectFindEdits(bool pAutoSelect)
{
  CEdit *pedFind;

  for( CMapFind::iterator it=m_mapEdit.begin(); it!=m_mapEdit.end(); it++)
  {
    pedFind = dynamic_cast<CEdit*>( ( *it).second);
    if(pedFind)
      pedFind->AutoSelect = pAutoSelect;
  }
}
//---------------------------------------------------------------------------
